﻿using System;
using System.Collections.Generic;
using System.Text;

using System.Drawing;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;

using NGE;

namespace MH
{
    [Serializable]
    public class Terrain
    {
        [Serializable]
        public class Layer
        {
            [Serializable]
            public class Tile
            {
                [Serializable]
                public class Frame
                {
                    public MemoryIndexer TextureIndexer;
                    public Rectangle DrawZone;
                    public double Rotation;
                    public Color FilterColor;

                    public Frame()
                    {
                        Rotation = 0;
                        FilterColor = Color.FromArgb(255, 255, 255, 255);
                        TextureIndexer = new MemoryIndexer();
                    }
                }

                public List<Frame> Frames = new List<Frame>();
                public Vector3 Location;
                public double Rotation;

                public Tile()
                {
                    Location = new Vector3();
                    Rotation = 0;
                }
            }

            public List<Tile> Tiles = new List<Tile>();

            public bool Visible;

            public Layer()
            {
                Visible = true;
            }

            public int GetTileIndex(Vector3 loc)
            {
                int i = 0;
                foreach (Tile t in Tiles)
                {
                    if (t.Location == loc)
                    {
                        return i;
                    }
                    i++;
                }
                return -1;
            }

            public void AddTile(Tile tile)
            {
                Tiles.Add(tile);
                //int i = GetIndex(tile.Location);
                //if (i == -1)
                //{

                //    return;
                //}
                //Tiles[i] = tile;
            }

            public void DelTile(Vector3 loc)
            {
                int i = GetTileIndex(loc);
                if (i == -1)
                {
                    return;
                }
                Tiles.RemoveAt(i);
            }
        }

        public List<Layer> Layers = new List<Layer>();

        public Terrain()
        {

        }
    }
    [Serializable]
    public class TileCode
    {        
        public Vector3 Location;
        public string Scrpit;
        public bool CHR;
        public bool MTL;
        public TileCode()
        {
            Location = new Vector3();
            CHR = true;
            MTL = true;
            Scrpit = "";
        }
    }
    [Serializable]
    public class TileCodeLayer : IDisposable
    {
        public List<TileCode> TileCodeSet = new List<TileCode>();
        int search(int x, int y, int z)
        {
            int i = 0;
            foreach (TileCode tc in TileCodeSet)
            {
                if (tc.Location.Equals(new Vector3(x, y, z)))
                {
                    return i;
                }
                i++;
            }
            return -1;
        }
        public void Dispose()
        {
            TileCodeSet.Clear();
        }
        public TileCode this[int x, int y]
        {
            get
            {
                int i = search(x, y, 0);
                if (i > -1)
                {
                    return TileCodeSet[i];
                }
                //TileCode tc = new TileCode();
                //tc.Location = new Vector3(-1,0,0);
                //tc.CHR = false;
                //tc.MTL = false;
                return null;
            }
            set
            {
                int i = search(x, y, 0);
                if (i == -1)
                {
                    TileCode tc = new TileCode();
                    tc.Location = new Vector3(x, y, 0);
                    TileCodeSet.Add(tc);
                    TileCodeSet[TileCodeSet.Count - 1] = value;
                    return;
                }
                TileCodeSet[i] = value;
            }
        }
        public TileCode this[Point p]
        {
            get
            {
                return this[p.X, p.Y];
            }
            set
            {
                this[p.X, p.Y] = value;
            }
        }
        public TileCode this[Vector3 p]
        {
            get
            {
                return this[(int)p.X, (int)p.Y];
            }
            set
            {
                this[(int)p.X, (int)p.Y] = value;
            }
        }
    }
    [Serializable]
    public class MonsterCode
    {
        public Rectangle Zone;
        public List<string> MonsterNames = new List<string>();
        public List<Spoil> Spoils = new List<Spoil>();
        /// <summary>
        /// 1-10000
        /// </summary>
        public int BattleRate;
        public string BattleMusic;
        public string this[int index]
        {
            get
            {
                return MonsterNames[index];
            }
        }
        public MonsterCode()
        {
 
        }
    }
    [Serializable]
    public class MonsterCodeLayer : IDisposable
    {
        public List<MonsterCode> MonsterCodeSet = new List<MonsterCode>();
        public MonsterCodeLayer()
        { }
        public void Dispose()
        {
            MonsterCodeSet.Clear();
        }
        int search(int x, int y, int z)
        {
            for (int i = 0; i < MonsterCodeSet.Count; i++)
            {
                if (x >= MonsterCodeSet[i].Zone.X)
                {
                    if (x < MonsterCodeSet[i].Zone.X + MonsterCodeSet[i].Zone.Width)
                    {
                        if (y >= MonsterCodeSet[i].Zone.Y)
                        {
                            if (y < MonsterCodeSet[i].Zone.Y + MonsterCodeSet[i].Zone.Height)
                            {
                                return i;
                            }
                        }
                    }
                }
            }
            return -1;
        }
        public void Add(MonsterCode mc)
        {
            MonsterCodeSet.Add(mc);
        }
        public MonsterCode this[int x, int y]
        {
            //set
            //{
            //    int i = search(x, y, 0);
            //    if (i < 0)
            //    {
            //        MonsterCodeSet.Add(value);
            //    }
            //}
            get
            {
                int i = search(x, y, 0);
                if (i > -1)
                {
                    return MonsterCodeSet[i];
                }
               
                return null;
            }
        }
        public MonsterCode this[int i]
        {
            get
            {
                return MonsterCodeSet[i];
            }
            set
            {
                if (value == null)
                {
                    MonsterCodeSet.RemoveAt(i);
                }
            }
        }
        public int Count
        {
            get
            {
                return MonsterCodeSet.Count;
            }
        }
    }
    [Serializable]
    public class EntryCode
    {
        public Rectangle Zone;
        public string ToSceneName;
        public string ToSceneFileName;
        public string Sound;
        public Vector3 DefaultLocation;
        public Direction DefaultDirection;
        public EntryCode()
        {
            Zone = new Rectangle();
            DefaultLocation = new Vector3();
        }
    }
    [Serializable]
    public class EntryCodeLayer : IDisposable
    {
        public EntryCodeLayer()
        {
 
        }
        public List<EntryCode> EntryCodeSet = new List<EntryCode>();
        int search(int x, int y, int z)
        {
            for (int i = 0; i < EntryCodeSet.Count; i++)
            {
                if (x >= EntryCodeSet[i].Zone.X)
                {
                    if (x < EntryCodeSet[i].Zone.X + EntryCodeSet[i].Zone.Width)
                    {
                        if (y >= EntryCodeSet[i].Zone.Y)
                        {
                            if (y < EntryCodeSet[i].Zone.Y + EntryCodeSet[i].Zone.Height)
                            {
                                return i;
                            }
                        }
                    }
                }
            }
            return -1;
        }
        public EntryCode this[int x, int y]
        {
            set
            {
                int i = search(x, y, 0);
                if (i < 0)
                {
                    EntryCode ec = new EntryCode();
                    ec.Zone = new Rectangle(x, y, 1, 1);
                    EntryCodeSet.Add(ec);
                    EntryCodeSet[EntryCodeSet.Count - 1] = value;
                    return;
                }
                if (value == null)
                {
                    EntryCodeSet.RemoveAt(i);
                    return;
                }
                EntryCodeSet[i] = value;
            }
            get
            {
                int i = search(x, y, 0);
                if (i < 0)
                {
                    return null;
                }
                return EntryCodeSet[i];
            }
        }

        public int Count
        {
            get
            {
                return EntryCodeSet.Count;
            }
        }

        public EntryCode this[int i]
        {
            get
            {
                return EntryCodeSet[i];
            }
            set
            {
                if (value == null)
                {
                    EntryCodeSet.RemoveAt(i);
                }
            }
        }
        public void Dispose()
        {
            EntryCodeSet.Clear();
        }
    }
    [Serializable]
    public class Scene : IDisposable
    {
        public string Name;
        public string MusicFileName;
        public DateTime CreateTime;
        public Size Size;
        public Size TileSize;
        public int FrameInterval;
        public Terrain Terrain;
        public Terrain.Layer.Tile ExtendTile;

        public string LoadScript;
        public string UnloadScript;

        public List<NImage> TileImageSet = new List<NImage>();
        public TileCodeLayer TileCodeLayer = new TileCodeLayer();
        public EntryCodeLayer EntryCodeLayer = new EntryCodeLayer();
        public MonsterCodeLayer MonsterCodeLayer = new MonsterCodeLayer();

        public List<Character> NPCs = new List<Character>();


        //public Character GetNPC(Vector3 loc)
        //{
        //    if (NPCs == null)
        //    {
        //        return null;
        //    }
        //    for (int i = 0; i < NPCs.Count; i++)
        //    {
        //        if (NPCs[i].Location == loc)
        //        {
        //            return NPCs[i];
        //        }
        //    }
        //    return null;
        //}


        //public void DelOPC(string name)
        //{
        //    int i = GetOPCIndex(name);
        //    if (i > -1)
        //    {
        //        OPCs.RemoveAt(i);
        //    }
        //}

        public Scene()
        {
            CreateTime = DateTime.Now;
            MusicFileName = "non_music";
            Name = "non_name";
            //Size = new Size(1, 1);
            FrameInterval = 300;
            Terrain = new Terrain();
            //TileSize = new Size(1, 1);
            TileImageSet = new List<NImage>();
        }
        public void Dispose()
        {
            for (int i = 0; i < TileImageSet.Count; i++)
            {
                if (TileImageSet[i] != null)
                {
                    TileImageSet[i].Dispose();
                }
            }
            TileImageSet.Clear();
            for (int i = 0; i < Terrain.Layers.Count; i++)
            {
                for (int j = 0; j < Terrain.Layers[i].Tiles.Count; j++)
                {
                    Terrain.Layers[i].Tiles[j].Frames.Clear();
                }
                Terrain.Layers[i].Tiles.Clear();
            }
            Terrain.Layers.Clear();
        }
        
        [NonSerialized]
        public Vector3 Location;
        [NonSerialized]
        Direction direction;
        [NonSerialized]
        int needMoveStep = 0;
        [NonSerialized]
        public float needMovePixel = 0f;
        [NonSerialized]
        float moveSpeed = 1f;

        public bool CanReach(Vector3 loc,bool is_in_mtl)
        {
            if (TileCodeLayer[loc] == null)
            {
                return true;
            }
            if (is_in_mtl == false)
            {
                if (TileCodeLayer[loc].CHR)
                {
                    return true;
                }
                return false;
            }
            else
            {
                if (TileCodeLayer[loc].MTL)
                {
                    return true;
                }
                return false;
            }
        }
        public bool CanReach(Character chr, Vector3 offset)
        {
            Vector3 loc = Util.Vector3AddVector3(chr.Location, offset);
            TileCode tc = TileCodeLayer[loc];
            Vector3 locc = loc;
            locc.X /= TileSize.Width;
            locc.Y /= TileSize.Height;
            if (locc.X < 0 || locc.Y < 0 || locc.X + 1 > Size.Width || locc.Y + 1 > Size.Height)
            {
                return false;
            }
            //try
            //{      
            if (TileCodeLayer[loc] == null)
            {
                return true;
            }
            if (chr.InMetalIndex < 0)
            {

                if (TileCodeLayer[loc].CHR)
                {
                    return true;
                }
                return false;
            }
            else
            {
                if (TileCodeLayer[loc].MTL)
                {
                    return true;
                }
                return false;
            }
            //}
            //catch 
            //{
            //    return false;
            //}
        }

        public int AddTileImage(Image image, Rectangle drawRect)
        {
            Image newimg = new Bitmap(drawRect.Width, drawRect.Height);
            Graphics g = Graphics.FromImage(newimg);
            g.DrawImage(image, 0, 0, drawRect, GraphicsUnit.Pixel);            

            NImage nImage = new NImage();
            nImage.GetData(newimg);

            int i = 0;
            foreach (NImage nimg in TileImageSet)
            {
                if (nimg != null)
                {
                    if (Util.NImageIsSame(nimg, nImage))
                    {
                        return i;
                    }
                }
                i++;
            }

            TileImageSet.Add(nImage);
            //TileSet[i].Init(d3ddev);
            return i;
        }
        
        public void Init(Device d3ddev)
        {
            foreach (NImage nimg in TileImageSet)
            {
                nimg.Init(d3ddev);
            }
        }

        public void Heartbeat()
        {
            if (needMovePixel > 0)
            {
                if (direction == Direction.U)
                {
                    Location.Y += moveSpeed;
                }
                else if (direction == Direction.L)
                {
                    Location.X += moveSpeed;
                }
                else if (direction == Direction.D)
                {
                    Location.Y -= moveSpeed;
                }
                else if (direction == Direction.R)
                {
                    Location.X -= moveSpeed;
                }
                if (needMovePixel < moveSpeed)
                {
                    needMovePixel = 0;
                }
                else
                {
                    needMovePixel -= moveSpeed;
                }
            }
            //for (int i = 0; i < OPCs.Count; i++)
            //{
            //    if (OPCs[i].InSceneName != Name)
            //    {
            //        OPCs.RemoveAt(i);
            //        i--;
            //    }
            //}
        }

        public void Move(Direction dir, int steps, float movespeed)
        {
            moveSpeed = movespeed;
            if (moveSpeed == 0)
            {
                return;
            }
            direction = dir;

            needMoveStep = steps;
            if (direction == Direction.U || direction == Direction.D)
            {
                {
                    needMovePixel = TileSize.Height * needMoveStep;
                }
            }
            else if (direction == Direction.L || direction == Direction.R)
            {
                {
                    needMovePixel = TileSize.Width * needMoveStep;
                }
            }
            //LastLocation = Location;
        }

        public void JumpTo(Vector3 loc, Vector3 centerPoint)
        {
            Location.X = -loc.X;
            Location.Y = -loc.Y;

            Location.X += centerPoint.X;
            Location.Y += centerPoint.Y;

            Location.X *= TileSize.Width;
            Location.Y *= TileSize.Height;
        }

        //public EntryCode IsAtJumpPoint(Vector3 loc)
        //{
        //    for (int i = 0; i < EntryCodeLayer.Count; i++)
        //    {
        //        EntryCode ec = EntryCodeLayer[i];
        //        if (Util.IsInZone(loc, ec.Zone))
        //        {
        //            return ec;
        //        }
        //    }
        //    return null;
        //}

        
    }
}
